#pragma once

#include <iostream>
#include <queue>
#include <pthread.h>
#include "Log.hpp"
#include "Task.hpp"

#define NUM 6

class ThreadPool
{
public:
    static ThreadPool* GetInstance() //获取对象，第一次获取对象时，初始化线程池，往后再次获取时不再初始化
    {
        static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER;
        if (single_instance == nullptr)
        {
            pthread_mutex_lock(&_mutex);
            if (single_instance == nullptr)
            {
                single_instance = new ThreadPool();
                single_instance->InitThreadPool();
            }
            pthread_mutex_unlock(&_mutex);
        }
        return single_instance; // 返回静态的对象指针
    }
    bool InitThreadPool() //初始化线程池
    {
        for (int i = 0; i < num; i++)
        {
            pthread_t tid;
            if (pthread_create(&tid, nullptr, ThreadRoutine, this) != 0)
            {
                LOG(FATAL, "create thread pool error!");
                return false;
            }
        }
        LOG(INFO, "create thread pool success!");
        return true;
    }
    void PushTask(const Task &task) //放任务进来，让队列里的线程自己自动执行
    {
        Lock();
        task_queue.push(task); //将任务放入任务队列
        Unlock();
        ThreadWakeup(); //唤醒在条件变量下等待的一个线程处理任务
    }
    void PopTask(Task &task) //任务执行完毕，干掉任务
    {
        task = task_queue.front();
        task_queue.pop();
    }
    static void *ThreadRoutine(void *args) //线程池中每个线程的执行函数
    {
        //线程函数的参数只能有一个void*，当传的是this指针，就能通过this指针访问任务队列
        ThreadPool *tp = (ThreadPool *)args;
        while (true)
        {
            Task t;
            tp->Lock();
            while (tp->TaskQueueIsEmpty()) //这里用while判断任务队列是否为空，防止线程被伪唤醒
            {
                tp->ThreadWait(); // 当我醒来的时候，一定是占有互斥锁的！
            }
            tp->PopTask(t);
            tp->Unlock();
            t.ProcessOn();
        }
    }
public:
    bool IsStop()
    {
        return stop;
    }
    bool TaskQueueIsEmpty()
    {
        return task_queue.size() == 0 ? true : false;
    }
    void Lock()
    {
        pthread_mutex_lock(&lock);
    }
    void Unlock()
    {
        pthread_mutex_unlock(&lock);
    }
    void ThreadWait()
    {
        pthread_cond_wait(&cond, &lock);
    }
    void ThreadWakeup()
    {
        pthread_cond_signal(&cond);
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&lock);
        pthread_cond_destroy(&cond);
    }

private: //搞成单例模式
    ThreadPool(int _num = NUM)
        :num(_num)
        ,stop(false)
    {
        pthread_mutex_init(&lock, nullptr);
        pthread_cond_init(&cond, nullptr);
    }
    ThreadPool(const ThreadPool &){}
    static ThreadPool *single_instance; //指向单例对象的指针

private:
    int num; //表示线程池中线程的个数
    bool stop;
    std::queue<Task> task_queue; //用于暂时存储未被处理的任务对象
    pthread_mutex_t lock; //互斥锁
    pthread_cond_t cond; //条件变量，当任务队列没有任务时，让线程进行等待，当任务队列中有任务时，通过该条件变量唤醒线程
};

ThreadPool* ThreadPool::single_instance = nullptr;